global u8 coldPeaksZone.sunrise = 0
global float coldPeaksZone.orangeTint
global float coldPeaksZone.sunriseTransparency
global float coldPeaksZone.darknessTransparency
global float coldPeaksZone.surpriseflashTransparency

global u8 coldPeaksZone.skippedCPZ

global s8 coldPeaksZone.moonPos
global u8 coldPeaksZone.moonOffset

global u8 coldPeaksZone.levelMusic
global u8 coldPeaksZone.levelMusicK
global u8 coldPeaksZone.easterEgg

global u8 ICZAlternateOnMode1 = 1

global float iceCapZone.teleporterCannon.warpTimer
global u16 iceCapZone.ringShooterTrail.y

global u8 coldPeaksZone.forceCPZ
global u8 coldPeaksZone.pickLevelMusic
global u8 coldPeaksZone.daytime
global u8 coldPeaksZone.daytimeK

global bool coldPeaksZone.loadedFromActSelect

#if !CZS_ACTIVE
	include toshc //Only if this is an SHC release.
#endif

include mechatails

include iceblock

include enemies

#define COLD_PEAKS_ZONE = 0x0130 //Version 1.3.0

//# post-update-hook
function void PostFrameUpdate()
{
	if coldPeaksZone.sunrise == 1 && level.restart && checkpoint.number < 4
		coldPeaksZone.sunrise = 0
	if Mods.isModActive("nighttime-launch-base-zone")
		coldPeaksZone.sunrise = 0
	base.PostFrameUpdate()

	if global.zone_act == 0x0501 && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0
	{
		Standalone.onLevelFinished()
		//Game.onTriggerNextZone(0x0500)

		coldPeaksZone.sunrise = 1
		coldPeaksZone.sunriseTransparency = 1.0f
		coldPeaksZone.darknessTransparency = 0.0f

		/*global.zone_act = 0x0500
		global.zone_act.apparent = 0x0501
		level.restart = 1*/

		checkpoint.number = 4
		checkpoint.number.backup = 4
		checkpoint.x = 0x6100
		checkpoint.y = 0x0540
		checkpoint.camera.x = 0x6029
		checkpoint.camera.y = 0x0490
		checkpoint.zone_act = 0x0500
		checkpoint.zone_act.apparent = 0x0501
		checkpoint.move_area.bottom = 0x0490
		checkpoint.layer_flags = 0x0e0f

		global.stage_type = 0

		coldPeaksZone.mechaTails.hasBeenFought = 1
		coldPeaksZone.mechaTails.resultsTimer = 92
		coldPeaksZone.mechaTails.introTimer = 185
		//6500
		coldPeaksZone.loadedFromActSelect = 1

		coldPeaksZone.loadMechaTailsPalette(false, false)
		coldPeaksZone.spawnMechaTailsObject()

		Standalone.onLevelStart()

		return
	}

	if Mods.isModActive("FBZ Background Crash") && Mods.getModPriority("FBZ Background Crash") > Mods.getModPriority("cold-peaks-zone")
	{
		if global.zone == 0x05 && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0
		{
			Renderer.drawText("oxyfont_regular:gradient:outline(0x000000ff,1,false):shadow(1,1,0.5f,0.8f)", getScreenWidth() / 2, 30, "please place fbz background crash\nbelow cold peaks zone", 0xFFFFFFFF, 5, 0, 0x1800, false)
			SpriteHandle fixyomodorder = Renderer.addSpriteHandle("coldpeakszone_fbzcrashconflict", 0 - 40 + getScreenExtend(), 0, 0x1800)
		}
	}
	if global.zone == 0x05 && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 //Custom stuff I have to load myself
	{
		System.loadExternalRawData("icz1_collision_alter", 0x279B60)
	}
	if global.zone != 0x06 && global.zone != 0x05
		coldPeaksZone.skippedCPZ = 0
	if global.zone_act == 0x0500 && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0
	{
		if global.act.apparent == 1
			coldPeaksZone.mechaTails.hasBeenFought = 1
		
		Renderer.enableDefaultPlane(2, false)

		if camera.position.x.u16 < 0x6023 && global.act.apparent == 0
		{
			coldPeaksZone.mechaTails.introTimer = 0
		}
		if coldPeaksZone.mechaTails.introTimer < 185
			++coldPeaksZone.mechaTails.introTimer
		if camera.position.x.u16 >= 0x6023 || global.act.apparent == 1
		{
			coldPeaksZone.mechaTailsStuff()
		}
		else if global.act.apparent == 0
		{
			coldPeaksZone.mechaTails.hitsRemaining = 16
			coldPeaksZone.mechaTails.resultsTimer = 0
			coldPeaksZone.mechaTails.hasBeenFought = 0
			level.boss_encounter = 0
		}
		if level.restart && Audio.isPlayingAudio(0x19)
			playMusic(MUSIC_CTRL_STOP)
		if coldPeaksZone.mechaTails.hasBeenFought == 1
		{
			if (allocDynamicObjectStd()) && coldPeaksZone.mechaTails.resultsTimer == 90 && (coldPeaksZone.mechaTails.position.y >= 0x0543 || coldPeaksZone.destroyMechaTails())
			{
				objA1.update_address = addressof(coldPeaksZone.callSignpost)
				coldPeaksZone.mechaTails.resultsTimer += 1
				coldPeaksZone.sunrise = 1
				playMusic(MUSIC_CTRL_FADEOUT)
			}
			if coldPeaksZone.mechaTails.resultsTimer == 91 && level.wait_for_results
			{
				coldPeaksZone.mechaTails.resultsTimer += 1
			}
		}
		else if !(coldPeaksZone.daytime || (getMainCharacter() == CHARACTER_KNUCKLES && coldPeaksZone.daytimeK))
		{
			coldPeaksZone.sunrise = 0
		}
		
		A0 = 0xffffb000
		coldPeaksZone.levelUpdate()
		Game.endSkippableCutscene()
		if (coldPeaksZone.daytime || (getMainCharacter() == CHARACTER_KNUCKLES && coldPeaksZone.daytimeK)) == 1
		{
			if coldPeaksZone.sunrise == 1
			{
				coldPeaksZone.sunriseTransparency = 1
				if coldPeaksZone.darknessTransparency > 0
					coldPeaksZone.darknessTransparency -= 0.05
			}
			else
			{
				if coldPeaksZone.darknessTransparency < 1
					coldPeaksZone.darknessTransparency += 0.05
			}
			coldPeaksZone.moonOffset = 512
		}
		else
		{
			if (!coldPeaksZone.sunrise && camera.position.x.u16 > 0x5a21 && camera.position.y.u16 < 0x0540)
			{
				if (coldPeaksZone.orangeTint < 1.0f)
					coldPeaksZone.orangeTint += 0.05f
			}
			else if (coldPeaksZone.orangeTint > 0.0f)
				coldPeaksZone.orangeTint -= 0.05f
			coldPeaksZone.orangeTint = clamp(coldPeaksZone.orangeTint, 0.0f, 1.0f)
			if (coldPeaksZone.sunrise == 1 && camera.position.x.u16 > (0x5f74 - getScreenExtend() + 40)) || coldPeaksZone.loadedFromActSelect
			{
				if coldPeaksZone.sunriseTransparency < 1
					coldPeaksZone.sunriseTransparency += 0.0075
				if coldPeaksZone.darknessTransparency > 0
				{
					if u16[0xffffb000 + 0x10] >= 0x6588
						coldPeaksZone.darknessTransparency -= 0.05
					else coldPeaksZone.darknessTransparency -= 0.0075
				}
			}
			else
			{
				coldPeaksZone.sunriseTransparency = 0
				coldPeaksZone.darknessTransparency = 1
			}
			coldPeaksZone.sunriseTransparency = clamp(coldPeaksZone.sunriseTransparency, 0.0f, 1.0f)
		}
		if coldPeaksZone.surpriseflashTransparency > 0
		{
			if u16[0xffffb000 + 0x10] >= 0x6588
				coldPeaksZone.surpriseflashTransparency -= 0.05
			else coldPeaksZone.surpriseflashTransparency -= 0.0075
			Renderer.drawRect(0, 0, getScreenWidth(), getScreenHeight(), 0xffffff00 + Math.roundToInt(coldPeaksZone.surpriseflashTransparency * 255.0f), 0xc001, false)
		}
	}
	
	#if CZS_ACTIVE
	if global.zone == 0x06 && coldPeaksZone.skippedCPZ == 1 && !customZoneSelect.shouldLoadAlternatesOnMode1()
	{
		customZoneSelect.useAlternates = 0
	}
	#else
	if global.zone == 0x06 && coldPeaksZone.skippedCPZ == 1
	{
		customZoneSelect.useAlternates = 0
	}
	#endif
	
	if global.zone_act == 0x0600 && coldPeaksZone.skippedCPZ == 0
	{
		startedLBZ1Fade = false
		LBZ1FadeProgress = 0x00
		startedLBZ2Fade = false
		LBZ2FadeProgress = 0x00
	}
}

//# address-hook(0x08b616) end(0x08b652)
function void fn08b616()
{
	if (coldPeaksZone.forceCPZ)
	{
		UnloadObject()
		return
	}
	base.fn08b616()
}

//# address-hook(0x08b5dc) end(0x08b608)
function void fn08b5dc()
{
	if (coldPeaksZone.forceCPZ)
	{
		UnloadObject()
		return
	}
	base.fn08b5dc()
}

//# address-hook(0x01e896)
function void fn01e896()
{
	if (objA0.position.x.u16 >= 0x46f0 && coldPeaksZone.forceCPZ)
	{
		UnloadObject()
		return
	}
	base.fn01e896()
}

function void CheckDistanceToPlayersAlt()
{
	if (u8[0xffffb000 + 0x20] != char.state.DISAPPEARED && u8[0xffffb04a + 0x20] != char.state.DISAPPEARED)
	{
		CheckDistanceToPlayers()
		return
	}
	else if (u8[0xffffb000 + 0x2e] != (control_flag.DISABLE_ANIMATION | control_flag.DISABLE_UPDATE | control_flag.DISABLE_INTERACTION))
		A1 = 0xffffb000
	else if (u8[0xffffb04a + 0x2e] != (control_flag.DISABLE_ANIMATION | control_flag.DISABLE_UPDATE | control_flag.DISABLE_INTERACTION))
		A1 = 0xffffb04a
	else return

	D2.s16 = objA0.position.x.u16 - objA1.position.x.u16
	D3.s16 = objA0.position.y.u16 - objA1.position.y.u16

	D0 = (D2.s16 < 0) ? 2 : 0
	D1 = (D3.s16 < 0) ? 2 : 0
	D2.u16 = abs(D2.s16)
	D3.u16 = abs(D3.s16)
}

//# address-hook(0x200418)
function void coldPeaksZone.ICZ2TeleporterCannonObjectUpdate()
{
	objA0.box_size.x = 0x50
	objA0.box_size.y = 0x50

	if (coldPeaksZone.forceCPZ)
	{
		u8[0xffff8880] = 0x83
		u8[0xffff8881] = 0x01
		u8[0xffff8882] = 0x01
	}
	
	CheckGroundCollision()
	if D1.s16 < -3
		objA0.position.y.u16 -= 6
	if D1.s16 > 3
		objA0.position.y.u16 += 6
	
	CheckDistanceToPlayersAlt()
	
	objA0.value26 = 0
	if D2.u16 < 8 && D3.u16 > 0x1a && D3.u16 < 0x60 && objA1.velocity.y > 0
	{
		if u8[A1 + 0x2e] != (control_flag.DISABLE_ANIMATION | control_flag.DISABLE_UPDATE | control_flag.DISABLE_INTERACTION)
			objA0.value26 = 1
		if D3.u16 > 0x1a && D3.u16 < 0x30
		{
			u8[A1 + 0x2e] = (control_flag.DISABLE_ANIMATION | control_flag.DISABLE_UPDATE | control_flag.DISABLE_INTERACTION)
			objA1.velocity.x = 0
			objA1.velocity.y = 0
			u8[A1 + 0x22] = 0
			u8[A1 + 0x04] = 0
			objA1.state = char.state.DISAPPEARED
		}
	}
	DrawObject()

	coldPeaksZone.skippedCPZ = 1
	if u8[0xffffb000 + 0x2e] == (control_flag.DISABLE_ANIMATION | control_flag.DISABLE_UPDATE | control_flag.DISABLE_INTERACTION) || u8[0xffffb04a + 0x2e] == (control_flag.DISABLE_ANIMATION | control_flag.DISABLE_UPDATE | control_flag.DISABLE_INTERACTION)
	{
		if (u8[0xffffb000 + 0x2e] == (control_flag.DISABLE_ANIMATION | control_flag.DISABLE_UPDATE | control_flag.DISABLE_INTERACTION))
		{
			objA0.value32 += 1

			if objA0.value32 == 80 || objA0.value32 == 40 || objA0.value32 == 2
				playSound(0xa7)
			if objA0.value32 == 120
				playSound(0xad)
			if objA0.value32 == 135
			{
				coldPeaksZone.skippedCPZ = 0
			#if CZS_ACTIVE
				TriggerNextZone(0x0600)
			#else
				customZoneSelect.useAlternates = 1
				TriggerNextZone(0x0500)
			#endif
			}
		}
	}
	else
	{
		objA0.value32 = 0
		coldPeaksZone.skippedCPZ = 1
	}

	if coldPeaksZone.forceCPZ == 1 && level.results_done == 0xff && objA1.position.x.u16 > objA0.position.x.u16 - 200
	{
		if A1 == 0xffffb04a
			player2.control_override = 0xff
		else player1.control_override = 0xff

		if objA1.position.x.u16 < objA0.position.x.u16 - 2
		{
			if A1 == 0xffffb04a
				control.tails.state = CONTROL_RIGHT
			else control.player1.state = CONTROL_RIGHT
		}
		else if objA1.position.x.u16 > objA0.position.x.u16 + 2
		{
			if A1 == 0xffffb04a
				control.tails.state = CONTROL_LEFT
			else control.player1.state = CONTROL_LEFT
		}
		else if (objA1.position.x.u16 >= objA0.position.x.u16 - 2 && objA1.position.x.u16 <= objA0.position.x.u16 + 2)
		{
			objA1.groundspeed = 0
			if !(objA1.flags2a & char.flag.IN_AIR) && objA1.velocity.x == 0
			{
				if A1 == 0xffffb04a
					control.tails = 0x2020
				else control.player1 = 0x2020
			}
			else if (objA1.flags2a & char.flag.IN_AIR) && objA1.velocity.y != 0
			{
				if A1 == 0xffffb04a
					control.tails = 0x2000
				else control.player1 = 0x2000
			}
			else
			{
				if A1 == 0xffffb04a
					control.tails = 0
				else control.player1 = 0
			}
		}
	}
}

//# address-hook(0x08657a) end(0x0865cc)
function void fn08657a()
{
	base.fn08657a()
	if (allocDynamicObjectStd()) && global.zone_act == 0x0501
	{
		objA1.update_address = addressof(coldPeaksZone.ICZ2TeleporterCannonObjectUpdate)
		objA1.position.x.u16 = 0x46b5
		objA1.position.y.u16 = objA0.position.y.u16
		objA1.render_flags = (render_flag.WORLD | render_flag.VISIBLE)
	}
}

//# address-hook(0x085e3a) end(0x085e50)
function void TriggerNextZone()
{
	if global.zone == 0x05 && customZoneSelect.alternateZoneSet == 0 && coldPeaksZone.skippedCPZ == 1
	{
		customZoneSelect.useAlternates = 0
		#if CZS_ACTIVE
		D0.u16 = Game.onTriggerNextZone(D0.u16) + 0x0100
		#else
		D0.u16 = Game.onTriggerNextZone(D0.u16)
		#endif
	}
	base.TriggerNextZone()
}

//# address-hook(0x02dcca)
function void LevelResults.AdvanceToNextAct()
{
	if customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 && global.zone_act == 0x0500
	{
		if (level.restart)
		{
			// Fix "frame-perfect reset" bug, but only for highest level of glitch fix setting
			if (Game.getSetting(SETTING_FIX_GLITCHES) >= 2)
			{
				UnloadObject()
				return
			}
		}

		if (objA0.countdown_value != 0)
		{
			--objA0.countdown_value
			return
		}

		if (u16[A0 + 0x30] != 0)
		{
			++objA0.value32
			return
		}

		level.wait_for_results = 0

		Standalone.onLevelFinished()
		
		global.act.apparent = 1
		
		// Show title card for Act 2
		objA0.update_address = addressof(TitleCard.Update)
		objA0.base_state = 0
		u8[A0 + 0x3e] = 0xff

		Standalone.onLevelStart()
		
		timer.alldata = 0
		checkpoint.number = 4
		checkpoint.x = 0x6100
		checkpoint.y = 0x0540
		Checkpoint.SaveCurrentState()
		
		level.results_done = 0xff
		chooseFittingMusic()
		stopCharacterWinPose(0xffffb000)
		stopCharacterWinPose(0xffffb04a)
	}
	else base.LevelResults.AdvanceToNextAct()
}

function void restartLevel()
{
	if customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 && global.zone_act == 0x0500 && global.act.apparent == 1
	{
		global.stage_type = 0
		global.in_extra_stage = 0

		level.restart = 1

		// This is needed only for restarting the AIZ 1 intro from within the fire transition (but does not hurt in all the other cases)
		camera.background.x = 0
		camera.background.y = 0

		Standalone.onRestartLevel()
	}
	else base.restartLevel()
}

//# address-hook(0x053740) end(0x053740)
//# address-hook(0x053886) end(0x05393c)
function void ICZ1.TransitionToOutdoorArea()
{
	if customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0
	{
	}
	else base.ICZ1.TransitionToOutdoorArea()
}

//# address-hook(0x053d5c) end(0x053d5c)
//# address-hook(0x053d68) end(0x053d74)
function void fn053d68()
{
	if customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0
	{
	}
	else base.fn053d68()
}

//# address-hook(0x05382c) end(0x053882)
function void fn05382c()
{
	if customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0
	{
		UpdateBackgroundScrolling.ICZ1.Indoors()
		UpdateBackgroundTiles.General()
		WriteScrollOffsets()
	}
	else base.fn05382c()
}

//# address-hook(0x053724) end(0x053728)
function void UpdateLevelScrolling.ICZ1()
{
	if customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0
	{
		//How DEZ does it
		Renderer.enableDefaultPlane(0, false)
		coldPeaksZone.renderBackground()
	}
	base.UpdateLevelScrolling.ICZ1()
}

//# address-hook(0x23e1aa) end(0x23e1d8)
function void fn23e1aa()
{
	if (coldPeaksZone.daytime || (getMainCharacter() == CHARACTER_KNUCKLES && coldPeaksZone.daytimeK))
		base.fn23e1aa()
	else fn23e20e()
}

//# address-hook(0x071440) end(0x071440)
function void fn071440()
{
	if (coldPeaksZone.daytime || (getMainCharacter() == CHARACTER_KNUCKLES && coldPeaksZone.daytimeK))
		base.fn071440()
}

//# address-hook(0x01bc60) end(0x01bcc2)
//# alias(fn01bc60) deprecated
function void Level.SetupLevelSize()
{
	if global.zone_act == 0x0500 && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0
	{
		u8[0xffffee30] = 0
		u8[0xffffee08] = 0
		player1.camera_lock = 0
		player2.camera_lock = 0
		u8[0xffffee39] = 0
		camera.update_routine = 0
		outro.wait_time = 0
		u16[0xfffff662] = 0

		A0 = 0x01bcc6 + global.zone * 16 + global.act * 8
		u16 minX = u16[A0]
		u16 maxX = 0x6bf0
		u16 minY = u16[A0+4]
		u16 maxY = u16[A0+6]

		move_area.left = minX
		move_area.right = maxX
		move_area.left.target = minX
		move_area.right.target = maxX
		move_area.left.player2 = minX
		move_area.right.player2 = maxX

		level.vertical_wrap = minY
		move_area.bottom.current = maxY
		move_area.top.target = minY
		move_area.bottom.target = maxY
		level.vertical_wrap.player2 = minY
		move_area.bottom.current.player2 = maxY

		camera.yoffset.player = 0x60
		camera.yoffset.tails = 0x60
		level.width.bitmask = 0xffff
		level.height.bitmask = 0xffff
		SetupCharacterAtStartPosition_ColdPeaksZone()
	}
	else base.Level.SetupLevelSize()
}

function void SetupCharacterAtStartPosition_ColdPeaksZone()
{
	if (checkpoint.number != 0)
	{
		SetupCharacterAtLastCheckpoint()
		D1.u16 = u16[0xffffb000 + 0x10]
		D0.u16 = u16[0xffffb000 + 0x14]
	}
	else
	{
		u16[0xffffb000 + 0x10] = 0x0780
		if getMainCharacter() == CHARACTER_KNUCKLES
		{
			u16[0xffffb000 + 0x14] = 0x0000
			camera.position.y.u16 = 0x0000
		}
		else
		{
			u16[0xffffb000 + 0x14] = 0x0385
			camera.position.y.u16 = 0x0300
		}
		camera.position.x.u16 = 0x06c3
		u16[0xffffb04a + 0x10] = 0x0000
		u16[0xffffb04a + 0x14] = 0x0000
		fn044a0c()
		return
	}
}

//# address-hook(0x053608) end(0x05365e)
function void InitLevelTiles.ICZ1()
{
	if customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0
	{
		level.height.bitmask = 0x07ff
		level.height.tilemask = 0x07f0
		level.chunksize.bitmask = 0x3c
		Level.GetCameraPosition()
		Level.InitialTilesFill()
	}
	else base.InitLevelTiles.ICZ1()
}

global bool coldPeaksZone.loadedPatterns

//Change stuff to make it work properly
function void coldPeaksZone.levelUpdate()
{
	if global.zone_act == 0x0500 && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0
	{
		if (timer.alldata > 10 && coldPeaksZone.loadedFromActSelect) || (timer.alldata < 10 && global.act.apparent == 1 && !coldPeaksZone.loadedFromActSelect)
		{
			coldPeaksZone.loadedFromActSelect = 0
			coldPeaksZone.spawnMechaTailsCutsceneObject()
		}
		if timer.seconds < 1 && global.act.apparent == 0
		{
			if char.state == char.state.DISAPPEARED
			{
				if global.framecounter % 2 == 0
				{
					SpriteHandle iceCapZone.ringShooterTrail = Renderer.addSpriteHandle("icecapzone_ringshooter_trail", u16[0xffffb000 + 0x10], u16[0xffffb000 + 0x14], 0x9e00)
					iceCapZone.ringShooterTrail.setFlags(0x20)
				}
				if level.framecounter & 0x05
					playSound(0xca)
			}
			else player1.control_override = 0x00
		}
		if timer.alldata > 2 && timer.alldata < 5 && global.act.apparent == 0
		{
			char.state = char.state.DISAPPEARED
			char.flags |= char.flag.IN_AIR
			char.velocity.x = 0
			char.velocity.y = 0x1000
			player1.control_override = 0xff
			control.player1 = 0
			if getMainCharacter() != CHARACTER_KNUCKLES
				char.flags |= char.flag.FACING_LEFT
		}
		if camera.position.x.u16 < 0x0200 && camera.position.y.u16 < 0x00e4
		{
			move_area.bottom.current = 0x0028
			move_area.bottom.target = 0x0028
		}
		else if camera.position.x.u16 > 0x5852 && camera.position.x.u16 < 0x61f0
		{
			move_area.bottom.target = 0x0490
			move_area.bottom.current = 0x0490
		}
		else if camera.position.x.u16 >= 0x61f0 && camera.position.x.u16 < 0x68ad
		{
			move_area.bottom.target = 0x0630
			move_area.bottom.current = 0x0630
		}
		else if camera.position.x.u16 >= 0x68ad
		{
			move_area.bottom.target = 0x02e0
			move_area.bottom.current = 0x02e0
		}
		else
		{
			move_area.bottom.target = 0x06c0
			move_area.bottom.current = 0x06c0
		}
		level.vertical_wrap = 0
		level.vertical_wrap.player2 = 0
		
		if camera.position.x.u16 >= 0x6500 && coldPeaksZone.loadedPatterns == 0
		{
			coldPeaksZone.loadedPatterns = 1
			fn02f77c()
			coldPeaksZone.spawnMechaTailsCutsceneObject()
			StartLoadingPatternsForZone()
		}
		if camera.position.x.u16 < 0x6500
			coldPeaksZone.loadedPatterns = 0
	}
}

//This takes care of more than the custom background.
function void coldPeaksZone.renderBackground()
{
	coldPeaksZone.skippedCPZ = 0
	
	u8 cameo1id = (global.framecounter / 600) % 23 + 1
	if (cameo1id > 3)
		cameo1id += 1

	string cameo = stringformat("coldpeakszone.cameo.%d", cameo1id)
	
	SpriteHandle coldpeakszone.cameo = Renderer.addSpriteHandle(cameo, 320, 144, 0xc001)
	coldpeakszone.cameo.setFlags(0x20|0x40)
	
	string cameo2 = stringformat("coldpeakszone.cameo2.%d", (global.framecounter / 600) % 14 + 1)
	
	SpriteHandle coldpeakszone.cameo2 = Renderer.addSpriteHandle(cameo2, 0x67c8, 0x0688, 0xc001)
	coldpeakszone.cameo2.setFlags(0x20|0x40)
	
	if global.zone_act == 0x0500
	{
		float divisionNum = 0.3f * coldPeaksZone.darknessTransparency
		float dB = (divisionNum / 2.0f)
		float dR = divisionNum / (coldPeaksZone.orangeTint * 4.0f + 1.0f)
		dB *= coldPeaksZone.orangeTint * 0.1f + 1.0f

		u32 blueTint = Math.lerp(0, u32(0xff), 1.0f - dB) * 0x100
		u32 greenTint = Math.lerp(0, u32(0xff), 1.0f - divisionNum) * 0x10000
		u32 redTint = Math.lerp(0, u32(0xff), 1.0f - dR) * 0x1000000

		u32 tint = blueTint + greenTint + redTint + 0x000000ff
		
		string piranha.key = stringformat("coldpeakszone_piranhaplant_%d", (global.framecounter / 6) % 2 + 1)
		SpriteHandle coldpeakszone.piranha1 = Renderer.addSpriteHandle(piranha.key, 0x25b8, 0x0668, 0x9f00)
		coldpeakszone.piranha1.setCoordinateSpace(1)
		coldpeakszone.piranha1.setTintColor(redTint / 255.0f / 0x1000000, greenTint / 255.0f / 0x10000, blueTint / 255.0f / 0x100, 1.0f)
		SpriteHandle coldpeakszone.piranha2 = Renderer.addSpriteHandle(piranha.key, 0x5fb8, 0x0398, 0x9f00)
		coldpeakszone.piranha2.setCoordinateSpace(1)
		coldpeakszone.piranha2.setFlipY(1)
		coldpeakszone.piranha2.setTintColor(redTint / 255.0f / 0x1000000, greenTint / 255.0f / 0x10000, blueTint / 255.0f / 0x100, 1.0f)

		u32 daytimeOpacity = (Math.roundToInt(coldPeaksZone.sunriseTransparency * 255.0f) / 16 * 16)

		if (global.whiteflash_timeout)
			Renderer.drawRect(0, 0, getScreenWidth(), getScreenHeight(), 0xffffff00 + u32(VInt.getBlendFactorForScreenFlash()), 0x1200, false)

		if (camera.position.x.u16 > 0x17a1 && camera.position.x.u16 < 0x26a1) || (camera.position.x.u16 > 0x3ca1 && camera.position.x.u16 < 0x446f) || (camera.position.x.u16 >= 0x446f && camera.position.x.u16 < 0x4d21 && camera.position.y.u16 < 0x05a1)
		{
			if (coldPeaksZone.daytime || (getMainCharacter() == CHARACTER_KNUCKLES && coldPeaksZone.daytimeK)) == 1
				coldPeaksZone.sunrise = 1
			
			for (u16 i; i < 3; ++i)
			{
				if (coldPeaksZone.sunriseTransparency > 0.0f)
				{
					Renderer.drawSpriteTinted("coldpeakszone_bg-trees-daytime_2", -(camera.foreground.x.u16 / 4) % 256 + (i * 256), 192, 0, 0, 0x1009, 0, 0xffffff00 + daytimeOpacity, 1.0f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-trees-daytime_1", -(camera.foreground.x.u16 / 6) % 256 + (i * 256), 160, 0, 0, 0x1008, 0, 0xffffff00 + daytimeOpacity, 1.0f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-trees-daytime_0", -(camera.foreground.x.u16 / 8) % 256 + (i * 256), 144, 0, 0, 0x1007, 0, 0xffffff00 + daytimeOpacity, 1.0f)

					Renderer.drawSpriteTinted("coldpeakszone_bg-sky-daytime_2", -(camera.foreground.x.u16 / 16 + (level.framecounter / 12)) % 256 + (i * 256), 18, 0, 0, 0x1006, 0, 0xffffffff, 1.0f, 1.0f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-sky-daytime_1", -(camera.foreground.x.u16 / 10 + (level.framecounter / 5)) % 256 + (i * 256), -8, 0, 0, 0x1006, 0, 0xffffff00 + daytimeOpacity, 1.0f, 1.0f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-sky-daytime_2", -(camera.foreground.x.u16 / 16 + (level.framecounter / 12)) % 256 + (i * 256), 150, 0, 0, 0x1006, 0, 0x4466dd00 + daytimeOpacity, 1.0f, -0.5f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-sky-daytime_1", -(camera.foreground.x.u16 / 10 + (level.framecounter / 5)) % 256 + (i * 256), 170, 0, 0, 0x1006, 0, 0x4466dd00 + daytimeOpacity, 1.0f, -0.5f)

					Renderer.drawSpriteTinted("coldpeakszone_bg-sky-daytime_0", -(camera.foreground.x.u16 / 32) % 256 + (i * 256), 0, 0, 0, 0x1005, 0, 0xffffff00 + daytimeOpacity, 1.0f)
				}
				if (coldPeaksZone.sunriseTransparency < 1.0f)
				{
					Renderer.drawSprite("coldpeakszone_bg-trees_2", -(camera.foreground.x.u16 / 4) % 256 + (i * 256), 192, 0, 0, 0x1004)
					Renderer.drawSprite("coldpeakszone_bg-trees_1", -(camera.foreground.x.u16 / 6) % 256 + (i * 256), 160, 0, 0, 0x1003)
					Renderer.drawSprite("coldpeakszone_bg-trees_0", -(camera.foreground.x.u16 / 8) % 256 + (i * 256), 144, 0, 0, 0x1002)

					Renderer.drawSpriteTinted("coldpeakszone_bg-sky_2", -(camera.foreground.x.u16 / 16 + (level.framecounter / 12)) % 256 + (i * 256), 48, 0, 0, 0x1001, 0, 0xffffffff, 1.0f, 1.0f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-sky_1", -(camera.foreground.x.u16 / 10 + (level.framecounter / 5)) % 256 + (i * 256), 0, 0, 0, 0x1001, 0, 0xffffffff, 1.0f, 1.0f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-sky_5", -(camera.foreground.x.u16 / 16 + (level.framecounter / 12)) % 256 + (i * 256), 138, 0, 0, 0x1001, 0, 0x00ffff88, 1.0f, -0.5f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-sky_4", -(camera.foreground.x.u16 / 10 + (level.framecounter / 5)) % 256 + (i * 256), 160, 0, 0, 0x1001, 0, 0x00ffff88, 1.0f, -0.5f)

					Renderer.drawSpriteTinted("coldpeakszone_bg-sky_3", (getScreenWidth() / 2) - (camera.foreground.x.u16 / 160), 48, 0, 0, 0x1000, 0, 0xffffffff, 1.0f, 1.0f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-sky_3", (getScreenWidth() / 2) - (camera.foreground.x.u16 / 160), 140, 0, 0, 0x1000, 0, 0xffffffff, 1.0f, -0.5f)

					Renderer.drawSprite("coldpeakszone_bg-sky_0", -(camera.foreground.x.u16 / 32) % 256 + (i * 256), 0, 0, 0, 0x1000)
				}
			}
		}
		else if camera.position.x.u16 > 0x5a21 && camera.position.y.u16 < 0x0540
		{
			if (coldPeaksZone.daytime || (getMainCharacter() == CHARACTER_KNUCKLES && coldPeaksZone.daytimeK)) == 1
				coldPeaksZone.sunrise = 1

			s16 sky.y = -(camera.foreground.y.u16 / 10)
			s16 angelisland.x = -(camera.position.x.u16 / 16) + getScreenExtend() + 1881

			if getMainCharacter() != CHARACTER_KNUCKLES
			{
				Renderer.drawSpriteTinted("coldpeakszone_bg-angelisland", angelisland.x, sky.y + 222, 0, 0, 0x1001, 0, 0xffffff00 + daytimeOpacity, 1.0f)
				Renderer.drawSpriteTinted("coldpeakszone_bg-angelisland-night", -(camera.position.x.u16 / 16) + getScreenExtend() + 1881, sky.y + 222, 0, 0, 0x1001, 0, 0xffffffff - daytimeOpacity, 1.0f)
			}
			else
			{
				Renderer.drawSpriteTinted("coldpeakszone_bg-angelisland-sky", angelisland.x - 12, sky.y + 100, 0, 0, 0x1001, 0, 0xffffff00 + daytimeOpacity, 1.0f)
				Renderer.drawSpriteTinted("coldpeakszone_bg-angelisland-sky-night", angelisland.x - 12, sky.y + 100, 0, 0, 0x1001, 0, 0xffffffff, 1.0f)
			}
			for (u16 i; i < 3; ++i)
			{
				if (coldPeaksZone.sunriseTransparency > 0.0f)
				{
					Renderer.drawSpriteTinted("coldpeakszone_bg-trees-daytime_3", -(camera.foreground.x.u16 / 2) % 256 + (i * 256), 272 - (camera.foreground.y.u16 / 3) + 230, 0, 0, 0x1009, 0, 0xffffff00 + daytimeOpacity, 1.0f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-trees-daytime_2", -(camera.foreground.x.u16 / 4) % 256 + (i * 256), 224 - (camera.foreground.y.u16 / 4) + 192, 0, 0, 0x1007, 0, 0xffffff00 + daytimeOpacity, 1.0f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-trees-daytime_1", -(camera.foreground.x.u16 / 6) % 256 + (i * 256), 192 - (camera.foreground.y.u16 / 5) + 154, 0, 0, 0x1005, 0, 0xffffff00 + daytimeOpacity, 1.0f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-trees-daytime_0", -(camera.foreground.x.u16 / 8) % 256 + (i * 256), 170 - (camera.foreground.y.u16 / 6) + 128, 0, 0, 0x1003, 0, 0xffffff00 + daytimeOpacity, 1.0f)
				}

				if (coldPeaksZone.sunriseTransparency < 1.0f)
				{
					u32 treetint = 0x88000000 + 0xff0000 + redTint + 0xff
					Renderer.drawSpriteTinted("coldpeakszone_bg-trees_3", -(camera.foreground.x.u16 / 2) % 256 + (i * 256), 272 - (camera.foreground.y.u16 / 3) + 230, 0, 0, 0x1008, 0, treetint, 1.0f, 1.0f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-trees_2", -(camera.foreground.x.u16 / 4) % 256 + (i * 256), 224 - (camera.foreground.y.u16 / 4) + 192, 0, 0, 0x1006, 0, treetint, 1.0f, 1.0f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-trees_1", -(camera.foreground.x.u16 / 6) % 256 + (i * 256), 192 - (camera.foreground.y.u16 / 5) + 154, 0, 0, 0x1004, 0, treetint, 1.0f, 1.0f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-trees_0", -(camera.foreground.x.u16 / 8) % 256 + (i * 256), 170 - (camera.foreground.y.u16 / 6) + 128, 0, 0, 0x1002, 0, treetint, 1.0f, 1.0f)
				}

				if (coldPeaksZone.sunriseTransparency > 0.0f)
				{
					Renderer.drawSpriteTinted("coldpeakszone_bg-sky-ending-daytime_0", -(camera.foreground.x.u16 / 12 + (level.framecounter / 3)) % 256 + (i * 256), sky.y, 0, 0, 0x1001, 0, 0xffffff00 + daytimeOpacity, 1.0f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-sky-ending-daytime_1", -(camera.foreground.x.u16 / 16 + (level.framecounter / 4)) % 256 + (i * 256), sky.y, 0, 0, 0x1001, 0, 0xffffff00 + daytimeOpacity, 1.0f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-sky-ending-daytime_2", -(camera.foreground.x.u16 / 24 + (level.framecounter / 5)) % 256 + (i * 256), sky.y, 0, 0, 0x1001, 0, 0xffffff00 + daytimeOpacity, 1.0f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-sky-ending-daytime_3", -(camera.foreground.x.u16 / 28) % 256 + (i * 256), sky.y, 0, 0, 0x1001, 0, 0xffffff00 + daytimeOpacity, 1.0f)
					Renderer.drawSpriteTinted("coldpeakszone_bg-sky-ending-daytime_4", -(camera.foreground.x.u16 / 24 + (level.framecounter / 5)) % 256 + (i * 256), sky.y, 0, 0, 0x1001, 0, 0xffffff00 + daytimeOpacity, 1.0f)
				}

				if (coldPeaksZone.sunriseTransparency < 1.0f)
				{
					Renderer.drawSprite("coldpeakszone_bg-sky-ending_0", -(camera.foreground.x.u16 / 12 + (level.framecounter / 3)) % 256 + (i * 256), sky.y, 0, 0, 0x1000)
					Renderer.drawSprite("coldpeakszone_bg-sky-ending_1", -(camera.foreground.x.u16 / 16 + (level.framecounter / 4)) % 256 + (i * 256), sky.y, 0, 0, 0x1000)
					Renderer.drawSprite("coldpeakszone_bg-sky-ending_2", -(camera.foreground.x.u16 / 24 + (level.framecounter / 5)) % 256 + (i * 256), sky.y, 0, 0, 0x1000)
					Renderer.drawSprite("coldpeakszone_bg-sky-ending_3", -(camera.foreground.x.u16 / 28) % 256 + (i * 256), sky.y, 0, 0, 0x1000)
					Renderer.drawSprite("coldpeakszone_bg-sky-ending_4", -(camera.foreground.x.u16 / 24 + (level.framecounter / 5)) % 256 + (i * 256), sky.y, 0, 0, 0x1000)
				}
			}
		}
		else
		{
			if (coldPeaksZone.daytime || (getMainCharacter() == CHARACTER_KNUCKLES && coldPeaksZone.daytimeK)) == 1
				coldPeaksZone.sunrise = 0
			for (u16 i; i < 6; ++i)
			{
				s16 x =	i % 3
				s16 y = i / 3

				Renderer.drawSprite("coldpeakszone_bg-cave_1", -(camera.foreground.x.u16 / 8) % 512 + (x * 512), -(camera.foreground.y.u16 / 3) % 256 + (y * 256), 0, 0, 0x1000)
				Renderer.drawSprite("coldpeakszone_bg-cave_0", -(camera.foreground.x.u16 / 6) % 512 + (x * 512), -(camera.foreground.y.u16 / 3) % 256 + (y * 256), 0, 0, 0x1001)
				Renderer.drawSprite("coldpeakszone_bg-cave_3", -(camera.foreground.x.u16 / 4) % 512 + (x * 512), -(camera.foreground.y.u16 / 3) % 256 + (y * 256), 0, 0, 0x1002)
				Renderer.drawSprite("coldpeakszone_bg-cave_2", -(camera.foreground.x.u16 / 3) % 512 + (x * 512), -(camera.foreground.y.u16 / 3) % 256 + (y * 256), 0, 0, 0x1003)
			}
		}
	}
}

//# address-hook(0x053a4c) end(0x053ad2)
function void fn053a4c()
{
	if (global.zone_act == 0x0500 && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0)
		UnloadObject()
	else base.fn053a4c()
}

//# address-hook(0x0539ac) end(0x053a0c)
function void fn0539ac()
{
	if !(global.zone_act == 0x0500 && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0)
		base.fn0539ac()
}

function u64 Standalone.getModdedSoundKey(u64 soundKey, u8 sfxId, u8 soundRegType)
{
	u8 pickDaytime
	if coldPeaksZone.pickLevelMusic == 0
		pickDaytime = (coldPeaksZone.daytime || (getMainCharacter() == CHARACTER_KNUCKLES && coldPeaksZone.daytimeK))
	else if coldPeaksZone.pickLevelMusic == 1
		pickDaytime = 1
	else pickDaytime = 0
	
    if global.zone_act == 0x0500 && (sfxId == 0x0b || sfxId == 0x0c) && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 
    {
		if coldPeaksZone.levelMusic == 0 && getMainCharacter() != CHARACTER_KNUCKLES|| (coldPeaksZone.levelMusicK == 0 && getMainCharacter() == CHARACTER_KNUCKLES) || (coldPeaksZone.levelMusic == 0 && coldPeaksZone.levelMusicK == 4 && getMainCharacter() == CHARACTER_KNUCKLES)
		{
			if ((coldPeaksZone.sunrise == 1 && (camera.position.x.u16 > (0x5f74 - getScreenExtend() + 40) || coldPeaksZone.loadedFromActSelect)) || pickDaytime) && coldPeaksZone.pickLevelMusic != 2
			{
				if coldPeaksZone.pickLevelMusic == 3
					return "pkmndp_route216night_md"
				return "pkmndp_route216day_md"
			}
			else
			{
				if coldPeaksZone.pickLevelMusic == 3
					return "pkmndp_route216day_md"
				return "pkmndp_route216night_md"
			}
		}
		else if coldPeaksZone.levelMusic == 1 && getMainCharacter() != CHARACTER_KNUCKLES|| (coldPeaksZone.levelMusicK == 1 && getMainCharacter() == CHARACTER_KNUCKLES) || (coldPeaksZone.levelMusic == 1&& coldPeaksZone.levelMusicK == 4 && getMainCharacter() == CHARACTER_KNUCKLES)
		{
			if ((coldPeaksZone.sunrise == 1 && (camera.position.x.u16 > (0x5f74 - getScreenExtend() + 40) || coldPeaksZone.loadedFromActSelect)) || pickDaytime) && coldPeaksZone.pickLevelMusic != 2
			{
				if coldPeaksZone.pickLevelMusic == 3
					return "thf_sukarabefight3"
				return "thf_sukarabefight1"
			}
			else
			{
				if coldPeaksZone.pickLevelMusic == 3
					return "thf_sukarabefight1"
				return "thf_sukarabefight3"
			}
		}
		else if coldPeaksZone.levelMusic == 2 && getMainCharacter() != CHARACTER_KNUCKLES || (coldPeaksZone.levelMusicK == 2 && getMainCharacter() == CHARACTER_KNUCKLES) || (coldPeaksZone.levelMusic == 2 && coldPeaksZone.levelMusicK == 4 && getMainCharacter() == CHARACTER_KNUCKLES)
		{
			if ((coldPeaksZone.sunrise == 1 && (camera.position.x.u16 > (0x5f74 - getScreenExtend() + 40) || coldPeaksZone.loadedFromActSelect)) || pickDaytime) && coldPeaksZone.pickLevelMusic != 2
			{
				if coldPeaksZone.pickLevelMusic == 3
					return "sa3_twinklesnow1"
				return "sa1_icemountain1"
			}
			else
			{
				if coldPeaksZone.pickLevelMusic == 3
					return "sa1_icemountain1"
				return "sa3_twinklesnow1"
			}
		}
		else if coldPeaksZone.levelMusic == 3 && getMainCharacter() != CHARACTER_KNUCKLES || (coldPeaksZone.levelMusicK == 3 && getMainCharacter() == CHARACTER_KNUCKLES) || (coldPeaksZone.levelMusic == 3 && coldPeaksZone.levelMusicK == 4 && getMainCharacter() == CHARACTER_KNUCKLES)
		{
			if ((coldPeaksZone.sunrise == 1 && (camera.position.x.u16 > (0x5f74 - getScreenExtend() + 40) || coldPeaksZone.loadedFromActSelect)) || pickDaytime) && coldPeaksZone.pickLevelMusic != 2
			{
				if coldPeaksZone.pickLevelMusic == 3
					return "pkmndp_route216night"
				return "pkmndp_route216day"
			}
			else
			{
				if coldPeaksZone.pickLevelMusic == 3
					return "pkmndp_route216day"
				return "pkmndp_route216night"
			}
		}
    }
	if global.zone_act == 0x0500 && (sfxId == 0x19) && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0
    {
		if coldPeaksZone.mechaTails.hitsRemaining < 5
			return "3db_boss2"
		else return "3db_boss1"
    }
    return base.Standalone.getModdedSoundKey(soundKey, sfxId, soundRegType)
}

//# address-hook(0x23de96) end(0x23dec4)
function void fn23de96()
{
	if customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0
	{
		u8[0xffffeee8] = 0xff
		fn23dec6()
	}
	else base.fn23de96()
}

//# address-hook(0x039b66) end(0x039c4e)
function void fn039b66()
{
	if customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0
	{
		move_area.left = 0x0000
		objA0.update_address = 0x039676
		u8[A2 + 0x2e] = 0
	}
	else base.fn039b66()
}

//# address-hook(0x05366a) end(0x05366a)
//# address-hook(0x053682) end(0x05369e)
function void fn053682()
{
	if customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0
	{
		fn053672()
	}
	else base.fn053682()
}

//# address-hook(0x00244e) end(0x002506)
function void LevelPaletteUpdate.ICZ()
{
	base.LevelPaletteUpdate.ICZ()
	if customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0
	{
		u32[0xfffffc78] = u32[0xfffffc58]
	}
}

//# address-hook(0x0393ee) end(0x039434)
function void fn0393ee()
{
	if customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0
	{
		objA0.update_address = 0x039676
		u8[A2 + 0x2e] = 0
		tails.ai_routine = 0x0006
		tails.respawn_counter = 0
	}
	else base.fn0393ee()
}

//# address-hook(0x053ad4) end(0x053b9c)
function void fn053ad4()
{
	if customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0
	{
		
	}
	else base.fn053ad4()
}

//# address-hook(0x010bba) end(0x010c8e)
function void Character.UpdateNormalState.Sonic()
{
	coldPeaksZone.moonwalk()
	base.Character.UpdateNormalState.Sonic()
}

//# address-hook(0x0137c4) end(0x0138f4)
function void Character.UpdateNormalState.Tails()
{
	if getMainCharacter() == CHARACTER_TAILS
		coldPeaksZone.moonwalk()
	base.Character.UpdateNormalState.Tails()
}

//# address-hook(0x01656c) end(0x016640)
function void Character.UpdateNormalState.Knuckles()
{
	coldPeaksZone.moonwalk()
	base.Character.UpdateNormalState.Knuckles()
}

global u8 coldPeaksZone.minMoonwalkDelay

function void coldPeaksZone.moonwalk()
{
	if coldPeaksZone.easterEgg == 0
		return
	if global.zone_act == 0x0500
	{
		if customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 && !(super.active) && !(super.active.tails) && !(char.bonus_effect & char.bonus.SPEED_UP)
		{
			if control.player1 == 0x0c00 && char.flags == char.flag.FACING_LEFT
			{
				global.move.acceleration = 0x0200
				global.move.deceleration = 0x1000
				if getMainCharacter() == CHARACTER_TAILS
				{
					global.move.acceleration.tails = 0x0200
					global.move.deceleration.tails = 0x1000
				}
			}
			else if control.player1 != 0x0c00 && char.flags == char.flag.FACING_LEFT
			{
				global.move.acceleration = 0x000c
				global.move.deceleration = 0x0080
				if getMainCharacter() == CHARACTER_TAILS
				{
					global.move.acceleration.tails = 0x000c
					global.move.deceleration.tails = 0x0080
				}
			}
			if global.move.acceleration == 0x0200 && !(char.flags == char.flag.FACING_LEFT)
				global.move.acceleration = 0x0001
			if global.move.acceleration = 0x0006
				global.move.acceleration = 0x000c
			
			if getMainCharacter() == CHARACTER_TAILS
			{
				if global.move.acceleration.tails == 0x0200 && !(char.flags == char.flag.FACING_LEFT)
					global.move.acceleration.tails = 0x0001
				if global.move.acceleration.tails = 0x0006
					global.move.acceleration.tails = 0x000c
			}
		}
		if control.player1 == 0x0c00 && char.flags == char.flag.FACING_LEFT
		{
			if coldPeaksZone.minMoonwalkDelay < 10
				coldPeaksZone.minMoonwalkDelay += 1
			if !(Audio.isPlayingAudio("mjmw_billiejean")) && !(level.boss_encounter == 1) && coldPeaksZone.minMoonwalkDelay == 10
			{
				Audio.playAudio("mjmw_billiejean", 0)
			}
		}
		else if control.player1 != 0x0c00 && char.flags == char.flag.FACING_LEFT
		{
			if Audio.isPlayingAudio("mjmw_billiejean")
			{
				coldPeaksZone.minMoonwalkDelay = 0
				chooseFittingMusic()
			}
		}
		if Audio.isPlayingAudio("mjmw_billiejean") && !char.flags == char.flag.FACING_LEFT
		{
			coldPeaksZone.minMoonwalkDelay = 0
			chooseFittingMusic()
		}
	}
}

function void chooseFittingMusic()
{
	if (level.boss_encounter == 1) && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 && global.zone_act == 0x0500
	{
		if coldPeaksZone.mechaTails.hitsRemaining < 5
			Audio.playAudio("3db_boss2", 0)
		else Audio.playAudio("3db_boss1", 0)
	}
	else base.chooseFittingMusic()
}

function bool Standalone.onDrawVdpSpriteCompound(s16 px, s16 py, u8 size, u16 index, u16 renderQueue, u8 spriteCounter)
{
	float divisionNum = 0.3f * coldPeaksZone.darknessTransparency
	float dB = (divisionNum / 2.0f)
	float dR = divisionNum / (coldPeaksZone.orangeTint * 4.0f + 1.0f)
	dB *= coldPeaksZone.orangeTint * 0.1f + 1.0f

	u32 blueTint = Math.lerp(0, u32(0xff), 1.0f - dB) * 0x100
	u32 greenTint = Math.lerp(0, u32(0xff), 1.0f - divisionNum) * 0x10000
	u32 redTint = Math.lerp(0, u32(0xff), 1.0f - dR) * 0x1000000

	u32 tint = blueTint + greenTint + redTint + 0x000000ff

	if (objA0.update_address == 0x03887c) && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 && global.zone_act == 0x0500
	{
		Renderer.drawSpriteTinted("coldpeakszone_bridge", px, py, 0x00, (objA0.sprite_attributes & sprite_attribute.PRIORITY), 0x9d7e, 0, tint, 1.0f)
		return true
	}
	return base.Standalone.onDrawVdpSpriteCompound(px, py, size, index, renderQueue, spriteCounter)
}

function bool Standalone.onDrawVdpSprite(s16 px, s16 py, u8 size, u16 index, u16 renderQueue)
{
	float divisionNum = 0.3f * coldPeaksZone.darknessTransparency
	float dB = (divisionNum / 2.0f)
	float dR = divisionNum / (coldPeaksZone.orangeTint * 4.0f + 1.0f)
	dB *= coldPeaksZone.orangeTint * 0.1f + 1.0f

	u32 blueTint = Math.lerp(0, u32(0xff), 1.0f - dB) * 0x100
	u32 greenTint = Math.lerp(0, u32(0xff), 1.0f - divisionNum) * 0x10000
	u32 redTint = Math.lerp(0, u32(0xff), 1.0f - dR) * 0x1000000

	u32 tint = blueTint + greenTint + redTint + 0x000000ff

	s8 i = 0
	string key = "coldpeakszone_collapsingbridge"
	bool flip
	if index == 0x4001 || index == 0x4801
		key = "coldpeakszone_collapsingbridge2"
	if index == 0x4009
		i = 2
	if index == 0x4011
		i = 4
	if index >= 0x4801
		flip = true
	
	if (objA0.update_address == 0x020594) && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 && global.zone_act == 0x0500
	{
		if index == 0x4001 || index == 0x4009 || index == 0x4011 || index == 0x4801 || index == 0x4809 || index == 0x4811
			Renderer.drawSpriteTinted(key, px - (flip ? -i : i) + (flip ? 0 : 32), py, 0x00, flip ? 0 : 0x01, 0x9d7e, 0, tint, 1.0f)
		return true
	}
	if (objA0.update_address == 0x0205ce || objA0.update_address == 0x0205de || objA0.update_address == 0x020620) && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 && global.zone_act == 0x0500
	{
		if index == 0x4001 || index == 0x4009 || index == 0x4011 || index == 0x4801 || index == 0x4809 || index == 0x4811
			Renderer.drawSpriteTinted(key, px - (flip ? -i : i) + (flip ? -16 : 32), py, 0x00, flip ? 0 : 0x01, 0x9d7e, 0, tint, 1.0f)
		return true
	}
	if (objA0.update_address == 0x0480d4 && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 && global.zone_act == 0x0500)
	{
		if (index & sprite_attribute.FLIP_X)
			index &= ~sprite_attribute.FLIP_X

		if (index == (sprite_attribute.PALETTE.LINE0 | 0x04a4))
		{
			Renderer.drawVdpSprite(px, py, size, sprite_attribute.PALETTE.LINE1 | index + 4, renderQueue)
			return true
		}
		if (index == (sprite_attribute.PALETTE.LINE1 | 0x0332))
		{
			Renderer.drawSpriteTinted("dez_retracting_spring_base", px + 0x10, py + 8, 0, objA0.render_flags, renderQueue + 1, 0, tint, 1.0f)
			return true
		}
	}
	return base.Standalone.onDrawVdpSprite(px, py, size, index, renderQueue)
}

//# address-hook(0x023490) end(0x0234e0)
function void SpringDiagonal.Update()
{
	if customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 && global.zone_act == 0x0500
	{
		for (u8 characterIndex = 0; characterIndex < 2; ++characterIndex)
		{
			D1.u16 = 27
			D2.u16 = 16
			D4.u16 = objA0.position.x.u16
			A2 = 0x0236ea

			A1 = 0xffffb000 + characterIndex * 0x4a
			D6 = 3 + characterIndex
			if (abs(objA0.position.x.u16 - objA1.position.x.u16) < 0x10 && abs(objA0.position.y.u16 - objA1.position.y.u16) < 0x20)
				SpringDiagonal.ApplyToCharacter()
		}

		Object.animationUpdate(0x023722)
		D0.u16 = objA0.value32
		DrawOrUnloadObjectByD0()
	}
	else base.SpringDiagonal.Update()
}

//# address-hook(0x0234e6) end(0x0235cc)
//# alias(fn0234e6) deprecated
function void SpringDiagonal.ApplyToCharacter()
{
	if customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 && global.zone_act == 0x0500
	{
		if ((objA0.flags2a & 0x01) == 0)
		{
			D0.u16 = objA0.position.x.u16 - 4
			if (D0.u16 >= objA1.position.x.u16)
				return
			
			if objA1.velocity.x < 0x400
				return
		}
		else
		{
			D0.u16 = objA0.position.x.u16 + 4
			if (D0.u16 < objA1.position.x.u16)
				return
		}
		
		objA0.state.both = 0x0500
		objA1.velocity.y = -0x600
		objA1.position.y.u16 -= 2
		if ((objA0.flags2a & 0x01) == 0)
		{
			objA1.flags2a &= ~char.flag.FACING_LEFT
			objA1.position.x.u16 -= 6
			if objA1.velocity.x < 0x570
				objA1.velocity.x = 0x570
			objA1.groundspeed = objA1.velocity.x
		}
		else
		{
			objA1.flags2a |= char.flag.FACING_LEFT
			objA1.position.x.u16 += 6
			if objA1.velocity.x > -0x570
				objA1.velocity.x = -0x570
			objA1.groundspeed = objA1.velocity.x
		}

		u8[A1 + 0x05] = base_state.NORMAL
		objA1.state = char.state.STRAIGHTJUMP
		objA1.flags2a |= char.flag.IN_AIR
		objA1.flags2a &= ~char.flag.ON_OBJECT
		u8[A1 + 0x40] = 0

		if (objA0.subtype2c & 0x01)
		{
			u8[A1 + 0x20] = 0
			u8[A1 + 0x30] = (objA0.subtype2c & 0x02) ? 1 : 3		// "char.rotation.x.count"
			u8[A1 + 0x31] = 8										// "char.rotation.x.speed"

			if (u8[A1 + 0x2a] & char.flag.FACING_LEFT)
			{
				s8[A1 + 0x27] = -1		// Set x-rotation of character
				objA1.groundspeed = -1
			}
			else
			{
				s8[A1 + 0x27] = 1		// Set x-rotation of character
				objA1.groundspeed = 1
			}
		}

		D0.u8 = objA0.subtype2c & 0x0c
		if (D0.u8 == 0x04)
		{
			u8[A1 + 0x46] = 0x0c
			u8[A1 + 0x47] = 0x0d
		}
		if (D0.u8 == 0x08)
		{
			u8[A1 + 0x46] = 0x0e
			u8[A1 + 0x47] = 0x0f
		}
	}
	else base.SpringDiagonal.ApplyToCharacter()
}

function void SpringDiagonal.updateInternal(bool flipY)
{
	if customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 && global.zone_act == 0x0500
	{
		for (u8 characterIndex = 0; characterIndex < 2; ++characterIndex)
		{
			A1 = 0xffffb000 + characterIndex * 0x4a
			if objA1.velocity.x < 0x400
			{
				
			}
			else base.SpringDiagonal.updateInternal(flipY)
		}
	}
	else base.SpringDiagonal.updateInternal(flipY)
}

function bool Standalone.onWriteToSpriteTable(s16 px, s16 py, u16 renderQueue)
{
	if (objA0.update_address == 0x023490 && objA0.subtype2c == 0x33) && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 && global.zone_act == 0x0500
		return true
	if objA0.update_address == 0x0398a6 && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 && global.zone_act == 0x0500
		return true
	if objA0.mapping_offset == 0x3639c0 && objA0.subtype2c == 0 && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 && global.zone_act == 0x0500
	{
		Renderer.drawCustomSprite("coldpeakszone_knuxwall", px, py, 0x00, objA0.render_flags, renderQueue)
		return true
	}
	if objA0.update_address == 0x08a44a && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 && global.zone_act == 0x0500
	{
		Renderer.drawCustomSprite("coldpeakszone_unbreakwall", px, py, 0x00, objA0.render_flags, renderQueue)
		Renderer.drawCustomSprite("coldpeakszone_unbreakwall", px, py - 128, 0x00, objA0.render_flags, renderQueue)
		return true
	}
	if objA0.update_address == 0x08a258 && customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 && global.zone_act == 0x0500
	{
		Renderer.drawCustomSprite("coldpeakszone_walldebris", px, py, 0x00, objA0.render_flags, 0x9d7e)
		return true
	}
	if objA0.update_address == 0x200418
	{
		u16 rq = objA0.value26 ? 0x9f00 : 0x9eff
		Renderer.drawCustomSprite("icecapzone_teleportercannon", px, py - 37, 0x20, 0, rq)
		
		string key
		if ((240 - objA0.value32) / 60) < 4
			key = stringformat("icecapzone_teleporter_countdown%d", (160 - Math.roundToInt(objA0.value32)) / 40)
		else key = "icecapzone_teleporter_countdown4"
		if global.framecounter % 2 == 0
			Renderer.drawCustomSprite(key, px - 50, py - 37, 0x20, 0, 0x9eff)
		
		if objA0.value32 > 120
		{
			if global.framecounter % 2 == 0
				Renderer.drawCustomSprite("icecapzone_ringshooter_trail", px, py - ((objA0.value32 - 120) * 15), 0x10, 0, 0x9eff)
			if level.framecounter & 0x05
				playSound(0xca)
		}
		
		Renderer.drawCustomSprite("icecapzone_ringshooter_countdown", px - 50, py - 37, 0x20, 0, 0x9eff)
	}
	return base.Standalone.onWriteToSpriteTable(px, py, renderQueue)
}

//# address-hook(0x01be46) end(0x01bfae)
function void SetupCharacterAtStartPosition()
{
	if !(checkpoint.number != 0) && (global.zone_act == 0x0600) && !coldPeaksZone.skippedCPZ
	{
		if coldPeaksZone.destroyMechaTails()
		{
			u16[0xffffb000 + 0x10] = 0x00b0
			u16[0xffffb000 + 0x14] = 0x0440
			camera.position.x.u16 = 0x0000
			camera.position.y.u16 = 0x0400
			u8[0xffffb000 + 0x20] = char.state.DISAPPEARED
			u8[0xffffb000 + 0x2a] |= char.flag.IN_AIR
		}
		else
		{
			u16[0xffffb000 + 0x10] = 0x0070 + 24
			u16[0xffffb000 + 0x14] = 0x0280
			camera.position.x.u16 = 0x0000
			camera.position.y.u16 = 0x0300
			u8[0xffffb000 + 0x2a] |= char.flag.IN_AIR
			u8[0xffffb000 + 0x20] = char.state.ROLLING
			Audio.playAudio("coldpeakszone.mechatails.dash")
		}
	}
	else base.SetupCharacterAtStartPosition()
}

//# address-hook(0x032c6a) end(0x032d14)
function void fn032c6a()
{
	if (customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 && global.zone_act == 0x0500)
		fn04808e()
	else base.fn032c6a()
}

//# address-hook(0x0480d4) end(0x04819c)
function void fn0480d4()
{
	if (customZoneSelect.useAlternates == 1 && customZoneSelect.alternateZoneSet == 0 && global.zone_act == 0x0500)
	{
		objA0.sprite_attributes = (sprite_attribute.PALETTE.LINE1 | 0x0332)

		D0.u16 = u16[0xffffb000 + 0x14] - objA0.position.y.u16
		if (u8[0xffffb000 + 0x20] == char.state.GOT_HURT && u8[0xffffb000 + 0x2e] == control_flag.DISABLE_ANIMATION)
			D0.s16 = -0x61
		else if objA0.position.x.u16 > 0x5000
		{
			base.fn0480d4()
			return
		}

		if (D0.s16 < 0)
		{
			if (D0.s16 < -0x60 && u16[A0 + 0x34] != objA0.value32)
			{
				if (u16[A0 + 0x34] == 0)
				{
					playSound(0x9a)
				}
				u16[A0 + 0x34] += 8
			}
		}
		else
		{
			if (D0.s16 >= 0x30 && u16[A0 + 0x34] != 0)
			{
				D1.u16 = objA0.value32
				if (D1.u16 == u16[A0 + 0x34])
				{
					playSound(0x9a)
				}
				u16[A0 + 0x34] -= 8
			}
		}

		D0.s16 = u16[A0 + 0x34]
		if (((objA0.flags2a & 0x01) != 0) == ((objA0.flags2a & 0x02) != 0))
		{
			D0.s16 = -D0.s16
		}
		objA0.position.x.u16 = u16[A0 + 0x44] + D0.s16

		D1 = objA0.box_size.x
		D3 = 9
		D4.u16 = objA0.position.x.u16

		push(D4)
		push(D3)
		push(D2)
		push(D1)

		A1 = 0xffffb000
		D6 = 3		// object.flag.P1_ON_OBJECT
		PlatformCheckClimbOnForCharacterA1()
		if (objA0.flags2a & object.flag.P1_ON_OBJECT)
		{
			SpringVertical.ApplyToCharacter()
		}

		D1 = pop()
		D2 = pop()
		D3 = pop()
		D4 = pop()

		A1 = 0xffffb04a
		D6 = 4		// object.flag.P2_ON_OBJECT
		PlatformCheckClimbOnForCharacterA1()
		if (objA0.flags2a & object.flag.P2_ON_OBJECT)
		{
			SpringVertical.ApplyToCharacter()
		}

		Object.animationUpdate(0x0481a2)

		D0.u16 = u16[A0 + 0x44]
		DrawOrUnloadObjectByD0()
	}
	else base.fn0480d4()
}

//# address-hook(0x039a40) end(0x039a7e)
function void fn039a40()
{
	if !coldPeaksZone.skippedCPZ
	{
		coldPeaksZone.loadMechaTailsPalette(false, false)
		if timer.alldata > 30
			UnloadObject()
		u16[0xffffb04a + 0x10] = 0x0300
		u16[0xffffb04a + 0x14] = 0x0300
		tails.respawn_counter = 0
		tails.ai_routine = 0x02
		if coldPeaksZone.destroyMechaTails()
		{
			s16[0xffffb000 + 0x18]
			s16[0xffffb000 + 0x1a] = 0x1000
			player1.control_override = 0xff
			if !(u8[0xffffb000 + 0x2a] & char.flag.IN_AIR)
			{
				player1.control_override = 0x00
				UnloadObject()
			}
		}
		
		if s16[0xffffb000 + 0x1a] < 0xc00 && u16[0xffffb000 + 0x10] == 0x0070 + 24
		{
			if !(u8[0xffffb000 + 0x2a] & char.flag.IN_AIR)
				UnloadObject()
			coldPeaksZone.spawnMechaTailsCutsceneObject()
			s16[0xffffb000 + 0x1a] = 0xc00
		}
	}
	else base.fn039a40()
}

//# address-hook(0x053f22) end(0x053fa2)
function void UpdateLevelTiles.LBZ1()
{
	if timer.seconds < 1
	{
		if u8[0xffffb000 + 0x20] == char.state.DISAPPEARED
		{
			if global.framecounter % 2 == 0
			{
				SpriteHandle iceCapZone.ringShooterTrail = Renderer.addSpriteHandle("icecapzone_ringshooter_trail", u16[0xffffb000 + 0x10], u16[0xffffb000 + 0x14], 0x9e00)
				iceCapZone.ringShooterTrail.setFlags(0x20)
			}
			if level.framecounter & 0x05
				playSound(0xca)
			player1.control_override = 0xff
			control.player1 = 0
		}
		else player1.control_override = 0x00
	}
	base.UpdateLevelTiles.LBZ1()
}

//# address-hook(0x0007ea) end(0x000954)
function void VInt.Update.MainGame()
{
	base.VInt.Update.MainGame()
	// Dark palette effect
	if ((global.game_mode & 0x7c) == 0x0c) // check if we're in the main game
	{
		if (global.whiteflash_timeout <= 0 && global.zone == 0x05 && customZoneSelect.useAlternates && customZoneSelect.alternateZoneSet == 0)
		{
			float divisionNum = 0.3f * coldPeaksZone.darknessTransparency
			for (u16 i = 0; i < 0x40; ++i)
			{
				if ((i >= 0x2a && i <= 0x2d) || (i >= 0x31 && i <= 0x37) || (i >= 0x3c && i <= 0x3f))
				{
					if (i == 0x2c || i == 0x2d || i == 0x3c || i == 0x3d)
					{
						u16 blue = u8[0xfffffc00 + i * 2]
						u16 green = u8[0xfffffc01 + i * 2] / 0x10
						u16 red = u8[0xfffffc01 + i * 2] % 0x10
						red = Math.roundToInt(float(red) / (0.5f * Math.sin(2.0f * 3.1415f * 128 * float(global.framecounter.low)) + 1.5f))
						u16 color = (blue * 0x100) + (green * 0x10) + red
						Renderer.setPaletteEntryPacked(i, color)
					}
					continue
				}

				float dB = (divisionNum / 2.0f * !(i >= 0x2e && i <= 0x2f))
				float dR = divisionNum / (coldPeaksZone.orangeTint * 4.0f + 1.0f)
				dB *= coldPeaksZone.orangeTint * 0.1f + 1.0f

				u16 blue = u8[0xfffffc00 + i * 2]
				u16 green = u8[0xfffffc01 + i * 2] / 0x10
				u16 red = u8[0xfffffc01 + i * 2] % 0x10

				blue = Math.lerp(0, blue, 1.0f - dB)
				green = Math.lerp(0, green, 1.0f - divisionNum)
				red = Math.lerp(0, red, 1.0f - dR)

				u16 color = (blue * 0x100) + (green * 0x10) + red
				Renderer.setPaletteEntryPacked(i, color)
			}
		}
	}
}

//LBZ Morning palette stuff, made by Nabbup

global bool startedLBZ1Fade = false
global u8 LBZ1FadeProgress = 0x00
global bool startedLBZ2Fade = false
global u8 LBZ2FadeProgress = 0x00

// init variables for lbz1
//# address-hook(0x053e96) end(0x053f1e)
function void InitLevelTiles.LBZ1()
{
	if coldPeaksZone.skippedCPZ == 1 && !Mods.isModActive("nighttime-launch-base-zone")
	{
		startedLBZ1Fade = false
		if (checkpoint.number < 5)
			LBZ1FadeProgress = 0x00
		else
			LBZ1FadeProgress = 0xff
	}
	base.InitLevelTiles.LBZ1()
}

// init variables for lbz2
//# address-hook(0x054348) end(0x054368)
function void InitLevelTiles.LBZ2()
{
	base.InitLevelTiles.LBZ2()
	// reset lbz1 fading just in case
	if coldPeaksZone.skippedCPZ == 1 && !Mods.isModActive("nighttime-launch-base-zone")
	{
		LBZ1FadeProgress = 0x00
		startedLBZ1Fade = false
		LBZ2FadeProgress = 0x00
		startedLBZ2Fade = false
	}
}

//# address-hook(0x053f22) end(0x053fa2)
function void UpdateLevelTiles.LBZ1()
{
	if coldPeaksZone.skippedCPZ == 1 && !Mods.isModActive("nighttime-launch-base-zone")
	{
		if (isMainCharacter(CHARACTER_KNUCKLES) && u16[0xffffeec4] == 0x55 && !startedLBZ1Fade)
		{
			startedLBZ1Fade = true
			LBZ1FadeProgress = 0x00
		}
	}
	base.UpdateLevelTiles.LBZ1()
	if coldPeaksZone.skippedCPZ == 1 && !Mods.isModActive("nighttime-launch-base-zone")
	{
		handleUseottPalettes.LBZ1()
		if (startedLBZ1Fade)
			handleLBZ1Fade()
	}
}

function void copyPaletteDataFromTable(u8 index, u16 ramAddress)
{
	base.copyPaletteDataFromTable(index, ramAddress)
	if (index == 0x17) && coldPeaksZone.skippedCPZ == 1
		handleUseottPalettes.LBZ2()
}

//# address-hook(0x05436c) end(0x054378)
function void UpdateLevelTiles.LBZ2()
{
	base.UpdateLevelTiles.LBZ2()
	if coldPeaksZone.skippedCPZ == 1 && !Mods.isModActive("nighttime-launch-base-zone")
	{
		handleUseottPalettes.LBZ2()
		if (startedLBZ2Fade)
			handleLBZ2Fade()
	}
}

// tower crumbling in lbz1
//# address-hook(0x053ff8) end(0x0540ce)
function void fn053ff8()
{
	if (s16[0xffffeec4] < 0) && coldPeaksZone.skippedCPZ == 1 && !Mods.isModActive("nighttime-launch-base-zone")
	{
		startedLBZ1Fade = true
		LBZ1FadeProgress = 0x00
	}
	base.fn053ff8()
}

// entering eggmobile in lbz2
//# address-hook(0x08d2b6) end(0x08d33e)
function void fn08d2b6()
{
	base.fn08d2b6()
	if (objA0.update_address == 0x08d370) && coldPeaksZone.skippedCPZ == 1 && !Mods.isModActive("nighttime-launch-base-zone")
		startedLBZ2Fade = true
}

function void handleUseottPalettes.LBZ1()
{
	u64 key = "lbz1_dusk"
	if (LBZ1FadeProgress != 0)
		key = "lbz1_dawn"
	u16 numColors = System.loadExternalPaletteData(key, 0, 0x800000, 0x20)

	for (u8 i = 0; i < numColors; ++i)
	{
		if (i > 8 && i < 12)
			continue
		u32 rgba = u32[0x800000 + i * 4]
		if (rgba & 0xff000000)
		{
			if (globalComponentTintColorR == 0xff)
					u16[0xfffffc40 + i * 2] = packColorExt(rgba)
			else
				u16[0xfffffcc0 + i * 2] = packColorExt(rgba)
		}
	}
}

function void handleUseottPalettes.LBZ2()
{
	if (LBZ2FadeProgress != 0)
		return
	u64 key = "lbz2_dawn"
	u16 numColors = System.loadExternalPaletteData(key, 0, 0x800000, 0x20)

	for (u8 i = 0; i < numColors; ++i)
	{
		if (i > 8 && i < 12)
			continue
		u32 rgba = u32[0x800000 + i * 4]
		if (rgba & 0xff000000)
		{
			if (globalComponentTintColorR == 0xff)
					u16[0xfffffc40 + i * 2] = packColorExt(rgba)
			else
				u16[0xfffffcc0 + i * 2] = packColorExt(rgba)
		}
	}
}

function void handleLBZ2Fade()
{
	if (LBZ2FadeProgress == 0xff)
		return
	u32 address = 0xfffffc40
	u32 addressStart = 0x0A931C
	u64 key = "lbz2_dawn"
	u16 numColors = System.loadExternalPaletteData(key, 0, 0x800000, 0x20)

	for (u8 i = 0; i < numColors; ++i)
	{
		if (i > 11 && i < 16)
			continue
		u32 rgba = u32[0x800000 + i * 4]
		if (rgba & 0xff000000)
			u16[address + i * 2] = blendColorsPacked(packColorExt(rgba), u16[addressStart + i * 2], LBZ2FadeProgress)
	}
	LBZ2FadeProgress = min(u16(LBZ2FadeProgress + 4), 0xff)
}

function void handleLBZ1Fade()
{
	if (globalComponentTintColorR != 0xff)
		return
	u64 key = "lbz1_dusk"
	u16 numColors = System.loadExternalPaletteData(key, 0, 0x800000, 0x20)
	u64 key2 = "lbz1_dawn"
	u16 numColors2 = System.loadExternalPaletteData(key2, 0, 0x800080, 0x20)
	for (u8 i = 0; i < numColors; ++i)
	{
		if (i > 8 && i < 12)
			continue
		u32 rgba = u32[0x800000 + i * 4]
		u32 rgba2 = u32[0x800080 + i * 4]
		if (rgba & 0xff000000 && rgba2 & 0xff000000)
			u16[0xfffffc40 + i * 2] = blendColorsPacked(packColorExt(rgba), packColorExt(rgba2), LBZ1FadeProgress)
	}
	LBZ1FadeProgress = min(u16(LBZ1FadeProgress + 4), 0xff)
}
